import base64

from odoo import http
from odoo.http import request


class AgriAIApiController(http.Controller):
    """面向 Android 客户端的简易 JSON API。"""

    def _get_partner_id(self, payload):
        partner_data = payload or {}
        partner_id = partner_data.get('id')
        if partner_id:
            return partner_id
        name = partner_data.get('name')
        phone = partner_data.get('phone')
        email = partner_data.get('email')
        if not (name or phone or email):
            return False
        Partner = request.env['res.partner'].sudo()
        domain = []
        if phone:
            domain = ['|', ('phone', '=', phone), ('mobile', '=', phone)]
        elif email:
            domain = [('email', '=', email)]
        partner = Partner.search(domain, limit=1) if domain else Partner.search([('name', '=', name)], limit=1)
        if partner:
            return partner.id
        return Partner.create({
            'name': name or phone or email,
            'phone': phone,
            'mobile': phone,
            'email': email,
        }).id

    def _decode_image(self, image_b64):
        if not image_b64:
            return False
        try:
            return base64.b64decode(image_b64)
        except Exception:
            return False

    @http.route('/agri_ai/api/knowledge', type='json', auth='user', methods=['POST'], csrf=False)
    def knowledge(self, **payload):
        crop_id = payload.get('crop_id')
        limit = payload.get('limit', 20)
        include_pests = payload.get('include_pests', True)
        Disease = request.env['agri.disease'].sudo()
        Pest = request.env['agri.pest'].sudo()

        domain = [('active', '=', True)]
        if crop_id:
            domain.append(('crop_ids', 'in', crop_id))

        diseases = Disease.search(domain, limit=limit)
        result = {
            'diseases': [
                {
                    'id': rec.id,
                    'name': rec.name,
                    'type': rec.disease_type,
                    'severity': rec.severity,
                    'season_window': rec.season_window,
                    'monitoring_tips': rec.monitoring_tips,
                    'recommended_products': rec.recommended_products,
                    'symptoms': rec.symptoms,
                    'treatment': rec.treatment,
                    'prevention': rec.prevention,
                    'audio_summary': rec.audio_summary,
                }
                for rec in diseases
            ]
        }

        if include_pests:
            pests = Pest.search(domain, limit=limit)
            result['pests'] = [
                {
                    'id': rec.id,
                    'name': rec.name,
                    'type': rec.pest_type,
                    'active_seasons': rec.active_seasons,
                    'monitoring_tips': rec.monitoring_tips,
                    'recommended_products': rec.recommended_products,
                    'symptoms': rec.symptoms,
                    'treatment': rec.treatment,
                    'prevention': rec.prevention,
                    'audio_summary': rec.audio_summary,
                }
                for rec in pests
            ]

        return result

    @http.route('/agri_ai/api/detection/log', type='json', auth='user', methods=['POST'], csrf=False)
    def log_detection(self, **payload):
        Detection = request.env['agri.detection.session'].sudo()
        partner_id = self._get_partner_id(payload.get('partner', {}))
        vals = {
            'partner_id': partner_id,
            'crop_id': payload.get('crop_id'),
            'disease_id': payload.get('disease_id'),
            'disease_confidence': payload.get('disease_confidence'),
            'pest_id': payload.get('pest_id'),
            'pest_confidence': payload.get('pest_confidence'),
            'detected_labels': payload.get('detected_labels'),
            'advisory': payload.get('advisory'),
            'audio_script': payload.get('audio_script'),
            'location_lat': payload.get('lat'),
            'location_lng': payload.get('lng'),
            'location_accuracy': payload.get('accuracy'),
            'location_text': payload.get('location_text'),
            'model_name': payload.get('model_name'),
            'model_version': payload.get('model_version'),
            'source': payload.get('source') or 'android_online',
        }

        image_b64 = payload.get('image')
        image_bin = self._decode_image(image_b64)
        if image_bin:
            vals['image_1920'] = image_bin

        record = Detection.create(vals)
        auto_generate = payload.get('auto_generate_advice', True)
        auto_followup = payload.get('auto_followup', True)
        if auto_generate and not (vals.get('advisory') or vals.get('audio_script')):
            record.with_context(agri_auto_followup=auto_followup).action_generate_advisory()

        return {
            'id': record.id,
            'name': record.name,
            'state': record.state,
            'advisory': record.advisory,
            'audio_script': record.audio_script,
            'followup_date': record.followup_date,
        }

    @http.route('/agri_ai/api/dataset/upload', type='json', auth='user', methods=['POST'], csrf=False)
    def upload_dataset(self, **payload):
        Dataset = request.env['agri.dataset.entry'].sudo()
        partner_id = self._get_partner_id(payload.get('partner', {}))
        vals = {
            'detection_id': payload.get('detection_id'),
            'contributor_id': partner_id,
            'label_type': payload.get('label_type') or 'disease',
            'disease_id': payload.get('disease_id'),
            'pest_id': payload.get('pest_id'),
            'custom_label': payload.get('custom_label'),
            'status': payload.get('status') or 'draft',
            'split': payload.get('split') or 'train',
            'device_id': payload.get('device_id'),
            'model_version': payload.get('model_version'),
            'notes': payload.get('notes'),
            'crop_id': payload.get('crop_id'),
            'extra_meta': payload.get('extra_meta'),
            'annotation_format': payload.get('annotation_format') or 'yolo',
            'annotation_payload': payload.get('annotation_payload'),
        }
        image_b64 = payload.get('image')
        image_bin = self._decode_image(image_b64)
        if not image_bin:
            return {'error': '缺少有效图片'}
        vals['image_1920'] = image_bin
        record = Dataset.create(vals)
        return {
            'id': record.id,
            'name': record.name,
            'status': record.status,
        }

    @http.route('/agri_ai/api/model/latest', type='json', auth='user', methods=['POST'], csrf=False)
    def model_latest(self, **payload):
        ModelVersion = request.env['agri.model.version'].sudo()
        platform = payload.get('platform') or 'android'
        model_name = payload.get('model_name')
        domain = [('active', '=', True)]
        if model_name:
            domain.append(('model_name', '=', model_name))
        domain.append(('platform', 'in', [platform, 'generic']))
        version = ModelVersion.search(domain, limit=1, order='is_default desc, release_date desc, id desc')
        if not version:
            return {'error': 'no_version'}
        return {
            'id': version.id,
            'name': version.name,
            'model_name': version.model_name,
            'version_code': version.version_code,
            'platform': version.platform,
            'quantization': version.quantization,
            'file_url': version.file_url,
            'file_checksum': version.file_checksum,
            'file_size': version.file_size,
            'release_date': version.release_date,
            'min_app_version': version.min_app_version,
            'accuracy': version.accuracy,
            'notes': version.notes,
        }

    @http.route('/agri_ai/api/dataset/pull', type='json', auth='user', methods=['POST'], csrf=False)
    def dataset_pull(self, **payload):
        Dataset = request.env['agri.dataset.entry'].sudo()
        domain = []
        status = payload.get('status')
        if status:
            domain.append(('status', '=', status))
        label_type = payload.get('label_type')
        if label_type:
            domain.append(('label_type', '=', label_type))
        updated_after = payload.get('updated_after')
        if updated_after:
            domain.append(('write_date', '>=', updated_after))
        if payload.get('export_only', True):
            domain.append(('exported', '=', False))

        limit = min(max(payload.get('limit', 50), 1), 200)
        entries = Dataset.search(domain, limit=limit, order='create_date desc')
        include_image = payload.get('include_image', False)
        include_annotation = payload.get('include_annotation', True)

        def format_entry(rec):
            data = {
                'id': rec.id,
                'name': rec.name,
                'label_type': rec.label_type,
                'status': rec.status,
                'split': rec.split,
                'crop_id': rec.crop_id.id,
                'disease_id': rec.disease_id.id,
                'pest_id': rec.pest_id.id,
                'custom_label': rec.custom_label,
                'capture_time': rec.capture_time,
                'device_id': rec.device_id,
                'model_version': rec.model_version,
                'extra_meta': rec.extra_meta,
                'annotation_format': rec.annotation_format,
                'exported': rec.exported,
                'export_batch': rec.export_batch,
            }
            if include_annotation:
                data['annotation_payload'] = rec.annotation_payload
            if include_image and rec.image_1920:
                data['image'] = base64.b64encode(rec.image_1920).decode()
            return data

        return {
            'count': len(entries),
            'entries': [format_entry(rec) for rec in entries],
        }

    @http.route('/agri_ai/api/dataset/mark_exported', type='json', auth='user', methods=['POST'], csrf=False)
    def dataset_mark_exported(self, **payload):
        ids = payload.get('ids') or []
        if not ids:
            return {'error': 'missing_ids'}
        Dataset = request.env['agri.dataset.entry'].sudo()
        records = Dataset.browse(ids).exists()
        if not records:
            return {'error': 'not_found'}
        batch_name = payload.get('batch_name')
        batch = records.action_mark_exported(batch_name=batch_name)
        return {
            'batch': batch,
            'count': len(records),
        }

